#ifndef __PRO_CALL_BACK__
#define __PRO_CALL_BACK__

#include <unordered_map>
#include "IContainer.h"
#include "ISysResources.h"
#include "IPacket.h"

#define DATA_BGN_STR "3706{"


class CProCallback
{
private:
	template< typename T >
	static shared_ptr< T > Invoke(const char * pszClassName, const void * pvdParaVal, char * pszMsgTxt, const int iMsgTxtSize)
	{
		int iInstanceType = -1;
		shared_ptr< T > ptrRetVal = nullptr;
		void * ptrInvok = m_ptrKernel->Invoke(pszClassName, pvdParaVal, pszMsgTxt, iMsgTxtSize, iInstanceType);
		if (ptrInvok == nullptr) goto __end;
		if (iInstanceType == 1) ptrRetVal.reset(dynamic_cast<T *>(reinterpret_cast<IObject *>(ptrInvok)), [](T * ptrObj) {});
		else if (iInstanceType == 2) ptrRetVal.reset(dynamic_cast<T *>(reinterpret_cast<IObject *>(ptrInvok)));
	__end:
		return ptrRetVal;
	}

	template< typename T >
	static T * Instance(const char * pszClassName, const void * pvdParaVal, char * pszMsgTxt, const int iMsgTxtSize)
	{
		int iInstanceType = -1;
		T * ptrRetVal = nullptr;
		void * ptrInvok = m_ptrKernel->Invoke(pszClassName, pvdParaVal, pszMsgTxt, iMsgTxtSize, iInstanceType);
		if (iInstanceType == 2) ptrRetVal = dynamic_cast<T *>(reinterpret_cast<IObject *>(ptrInvok));
	__end:
		return ptrRetVal;
	}

	static void GetMsgId(const char *  pszAcceptNo, char * pszMsgId, int iLen)
	{
		memset((void *)pszMsgId, 0, iLen);
		m_ptrLock->Lock();
		if (m_mpAcceptNo.find(pszAcceptNo) != m_mpAcceptNo.end())
		{
			if (iLen > m_mpAcceptNo[pszAcceptNo].length())
			{
				memcpy((void *)pszMsgId, (void *)m_mpAcceptNo[pszAcceptNo].c_str(), m_mpAcceptNo[pszAcceptNo].length());
			}
			else
			{
				memcpy((void *)pszMsgId, (void *)m_mpAcceptNo[pszAcceptNo].c_str(), iLen - 1);
			}
		}
		m_ptrLock->Unlock();
	}
public:
	static void SetKernel(IKernel * ptrKernel)
	{
		m_ptrKernel = ptrKernel;
		m_ptrLock = Invoke<ILock>("CThreadLock", nullptr, nullptr, 0);
		m_ptrQueueOperation = Invoke<IQueueOperation>("CQueueOperation", nullptr, nullptr, 0);
		if (!m_ptrQueueOperation->IsQueueExist(TASK_QUEUE_NAME))
		{
			m_ptrQueueOperation->CreateQueue(TASK_QUEUE_NAME);
		}
	}

	static void AsynCallback(const char *p_pszAcceptSn, const unsigned char *p_pszDataBuff, int p_iDataLen)
	{
		m_ptrQueueOperation->PushTask(TASK_QUEUE_NAME, string(string(p_pszAcceptSn) + (strstr((char *)p_pszDataBuff, DATA_BGN_STR) + 4)).c_str());
	}


	static void SubCallback(const char *p_pszAcceptSn, const unsigned char *p_pszDataBuff, int p_iDataLen)
	{
		
		char szMsgId[CHAR_LEN_256] = { 0 };
		GetMsgId(p_pszAcceptSn, szMsgId, sizeof(szMsgId));
		if (szMsgId[0] != '\0')
		{
			int iLen = strlen(szMsgId);
			CREATE_PTR_DATA_PACKET(ptrData);
			char * ptrBuf = new char[iLen + p_iDataLen];
			memcpy((void *)ptrBuf, (void *)string(szMsgId).c_str(), iLen);
			memcpy((void *)(ptrBuf + iLen), (void *)p_pszDataBuff, p_iDataLen);
			ptrData->Parse((char *)ptrBuf, iLen + p_iDataLen);
			m_ptrQueueOperation->PushTask(TASK_QUEUE_NAME, ptrData);
			delete ptrBuf;
			ptrBuf = nullptr;
		}
	}

	static void RegAcceptNo(const char *  pszAcceptNo, const char * pszMsgId)
	{
		m_ptrLock->Lock();
		m_mpAcceptNo[pszAcceptNo] = pszMsgId;
		m_ptrLock->Unlock();
	}

private:
	static IKernel * m_ptrKernel;
	static shared_ptr<IQueueOperation> m_ptrQueueOperation;
	static shared_ptr<ILock> m_ptrLock;
	static unordered_map<string, string> m_mpAcceptNo;
};

#endif // !__PRO_CALL_BACK__

